/*
 * Copyright © 2005-2021 www.wondersoft.cn. All rights reserved.
 */

package me.ijleex.platform.framework.util;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;

/**
 * 生成随机密码工具类.
 *
 * <pre>{@code pwgen --help}</pre>
 *
 * @author liym
 * @since 2021-06-26 14:07 新建
 */
public abstract class RandomPasswordUtils {

    private static final ThreadLocalRandom RANDOM = ThreadLocalRandom.current();

    private static final String LETTERS = "abcdefghijklmnopqrstuvwxyz";
    private static final String NUMERALS = "0123456789";
    private static final String SYMBOLS = "~!@#$%^&*()_+/-=[]{};:'<>?.";

    private RandomPasswordUtils() {
    }

    /**
     * 生成指定长度的密码
     *
     * @param length 密码长度
     * @return 密码
     * @since 2021-06-26 14:17
     */
    public static String genPwd(int length) {
        return genPwd(true, true, true, length);
    }

    /**
     * 生成指定密码复杂度的密码
     *
     * @param capitalize 是否至少包含一个大写字母
     * @param numerals 是否至少包含一个数字
     * @param symbols 是否至少包含一个特殊符号
     * @param length 密码长度（8~30）
     * @return 密码
     * @since 2021-06-26 14:14
     */
    public static String genPwd(boolean capitalize, boolean numerals, boolean symbols, final int length) {
        if (length < 8 || length > 30) {
            return genPwd(capitalize, numerals, symbols, 10);
        }

        List<Character> list = new ArrayList<>(length);

        list.add(capitalize ? getCapitalLetter() : getLetter());
        list.add(numerals ? getNumber() : getLetter());
        list.add(symbols ? getSymbol() : getLetter());
        list.add(getLetter());

        for (int i = 4; i < length; i++) {
            int chType = RANDOM.nextInt(4);
            list.add(getRandomChar(capitalize, numerals, symbols, chType));
        }

        // 打乱顺序
        Collections.shuffle(list);

        StringBuilder retVal = new StringBuilder(list.size());
        for (Character ch : list) {
            retVal.append(ch);
        }
        return retVal.toString();
    }

    /**
     * 获取随机字符
     */
    private static char getRandomChar(String str) {
        return str.charAt(RANDOM.nextInt(str.length()));
    }

    /**
     * 获取随机小写字符
     */
    private static char getLetter() {
        return getRandomChar(LETTERS);
    }

    /**
     * 获取随机大写字符
     */
    private static char getCapitalLetter() {
        return Character.toUpperCase(getLetter());
    }

    /**
     * 获取随机数字
     */
    private static char getNumber() {
        return getRandomChar(NUMERALS);
    }

    /**
     * 获取随机特殊字符
     */
    private static char getSymbol() {
        return getRandomChar(SYMBOLS);
    }

    /**
     * 获取指定类型的随机字符
     *
     * @param type 字符类型：0/1/2/3
     * @return 随机字符
     */
    private static char getRandomChar(boolean capitalize, boolean numerals, boolean symbols, int type) {
        switch (type) {
            case 0:
                return capitalize ? getCapitalLetter() : getLetter();
            case 1:
                return numerals ? getNumber() : getLetter();
            case 2:
                return symbols ? getSymbol() : getLetter();
            default:
                return getLetter();
        }
    }

}
